home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS03.ADF / C / kermit.c < prev    next >
C/C++ Source or Header  |  1986-04-02  |  33KB  |  938 lines

  1.  
  2. /*
  3.  *      K e r m i t  File Transfer Utility
  4.  *
  5.  *      UNIX Kermit, Columbia University, 1981, 1982, 1983
  6.  *      Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz
  7.  *
  8.  *      usage: kermit [csr][dlbe line baud escapechar] [f1 f2 ...]
  9.  *
  10.  *      where c=connect, s=send [files], r=receive, d=debug,
  11.  *      l=tty line, b=baud rate, e=escape char (decimal ascii code).
  12.  *      For "host" mode Kermit, format is either "kermit r" to
  13.  *      receive files, or "kermit s f1 f2 ..." to send f1 .. fn.
  14.  *
  15.  *
  16.  *      Fixed up again for Unix, Jim Guyton 7/13/83 (Rand Corp)
  17.  */
  18.  
  19. /*
  20.  *      Hacked up for the Amiga, Raymond S. Brand 19851130->
  21.  */
  22.  
  23. #include <exec/types.h>
  24. #include <stdio.h>                      /* Standard UNIX definitions */
  25. #include <exec/exec.h>
  26. #include <devices/serial.h>
  27.  
  28. /* Conditional Compilation: 0 means don't compile it, nonzero means do */
  29.  
  30. /* Symbol Definitions */
  31.  
  32. #define MAXPACK         94      /* Maximum packet size */
  33. #define SOH             1       /* Start of header */
  34. #define SP              32      /* ASCII space */
  35. #define CR              13      /* ASCII Carriage Return */
  36. #define DEL             127     /* Delete (rubout) */
  37. #define CTRLD           4
  38. #define BRKCHR          CTRLD   /* Default escape character for CONNECT */
  39.  
  40. #define MAXTRY          5       /* Times to retry a packet */
  41. #define MYQUOTE         '#'     /* Quote character I will use */
  42. #define MYPAD           0       /* Number of padding characters I will need */
  43. #define MYPCHAR         0       /* Padding character I need */
  44. #define MYEOL           '\n'    /* End-Of-Line character I need */
  45. #define MYTIME          10      /* Seconds after which I should be timed out */
  46. #define MAXTIM          20      /* Maximum timeout interval */
  47. #define MINTIM          2       /* Minumum timeout interval */
  48.  
  49.  
  50.  
  51. /* Global Variables */
  52.  
  53. int     size,                   /* Size of present data */
  54.         n,                      /* Message number */
  55.         rpsiz,                  /* Maximum receive packet size */
  56.         spsiz,                  /* Maximum send packet size */
  57.         pad,                    /* How much padding to send */
  58.         timint,                 /* Timeout for foreign host on sends */
  59.         numtry,                 /* Times this packet retried */
  60.         oldtry,                 /* Times previous packet retried */
  61.         fd,                     /* File pointer of file to read/write */
  62.         image,                  /* -1 means 8-bit mode */
  63.         debug;                  /* -1 means debugging */
  64.  
  65. char    state,                  /* Present state of the automaton */
  66.         padchar,                /* Padding character to send */
  67.         eol,                    /* End-Of-Line character to send */
  68.         escchr,                 /* Connect command escape character */
  69.         quote,                  /* Quote character in incoming data */
  70.         *filnam,                /* Current file name */
  71.         recpkt[MAXPACK],        /* Receive packet buffer */
  72.         packet[MAXPACK];        /* Packet buffer */
  73.  
  74.  
  75. struct IOExtSer SerMsg;
  76. struct MsgPort Serreplyport;
  77.  
  78. int argc;                               /* Character pointer for */
  79. char **argv;                            /*  command line arguments */
  80.  
  81. /*
  82.  *      m a i n
  83.  *
  84.  *      Main routine - parse command and options, set up the
  85.  *      serial.device, and dispatch to the appropriate routine.
  86.  */
  87.  
  88. main(ARGC,ARGV)
  89. int ARGC;                               /* Character pointer for */
  90. char **ARGV;                            /*  command line arguments */
  91. {
  92.   char *cp;                             /* char pointer */
  93.   int speed, cflg, rflg, sflg;          /* speed of serial.device */
  94.                                         /* flags for CONNECT, RECEIVE, SEND */
  95.  
  96.   argc = ARGC;
  97.   argv = ARGV;
  98.  
  99.   if (argc < 2) usage();                /* Make sure there's a command line. */
  100.  
  101.   cp = *++argv; argv++; argc -= 2;      /* Set up pointers to args */
  102.  
  103. /* Initialize this side's SEND-INIT parameters */
  104.  
  105.   eol = CR;                             /* EOL for outgoing packets */
  106.   quote = MYQUOTE;                      /* Standard control-quote char "#" */
  107.   pad = 0;                              /* No padding */
  108.   padchar = NULL;                       /* Use null if any padding wanted */
  109.  
  110.   speed = cflg = sflg = rflg = 0;       /* Turn off all parse flags */
  111.   image = FALSE;                        /* Default to 7-bit mode */
  112.   escchr = BRKCHR;                      /* Default escape character */
  113.  
  114.   while ((*cp) != NULL)                 /* Get a character from the cmd line */
  115.     switch (*cp++)                      /* Based on what the character is, */
  116.      {                                  /*  do one of the folloing */
  117.       case '-': break;                  /* Ignore dash (UNIX style) */
  118.       case 'c': cflg++; break;          /* C = CONNECT command */
  119.       case 's': sflg++; break;          /* S = SEND command */
  120.       case 'r': rflg++; break;          /* R = RECEIVE command */
  121.       case 'e': if (argc--)             /* E = specify escape char */
  122.                   escchr = atoi(*argv++); /*  as ascii decimal number */
  123.                 else usage();
  124.                 if (debug) fprintf(stderr,"escape char is ascii %d\n",escchr);
  125.                 break;
  126.       case 'b': if (argc--) speed = atoi(*argv++); /* Set baud rate */
  127.                   else usage();
  128.                 if (debug) fprintf(stderr,"speed %d\n",speed); break;
  129.  
  130.       case 'i': image = TRUE; break;    /* Image (8-bit) mode */
  131.  
  132.       case 'd': debug = TRUE; break;    /* Debug mode */
  133.      }
  134.  
  135. /* Done parsing */
  136.  
  137.   if ((cflg+sflg+rflg) != 1) usage();   /* Only one command allowed */
  138.   
  139. /* Put the serial.device into the correct modes */
  140.  
  141.   Serreplyport.mp_SigBit = AllocSignal(-1);
  142.   Serreplyport.mp_SigTask = (struct Task *)(FindTask(0));
  143.   Serreplyport.mp_Flags = 0;
  144.  
  145.   SerMsg.io_SerFlags = SERF_XDISABLED | /* SERF_SHARED | */ SERF_RAD_BOOGIE;
  146.  
  147.   OpenDevice(SERIALNAME,0,&SerMsg,0);
  148.   if(SerMsg.IOSer.io_Error != 0)
  149.    {
  150.     printf("\nserial.device open error = %u:\n\n"
  151.            ,(unsigned)(SerMsg.IOSer.io_Error));
  152.     exit(0);
  153.    }
  154.  
  155.   SerMsg.IOSer.io_Message.mn_ReplyPort = &Serreplyport;
  156.   SerMsg.io_Baud = speed;
  157.   SerMsg.io_ReadLen = 8;
  158.   SerMsg.io_WriteLen = 8;
  159.   SerMsg.io_StopBits = 1;
  160.   SerMsg.IOSer.io_Command = SDCMD_SETPARAMS;
  161.  
  162.   DoIO(&SerMsg);
  163.   if(SerMsg.IOSer.io_Error != 0)
  164.    {
  165.     printf("\nserial.device set param error = %u:\n\n"
  166.            ,(unsigned)(SerMsg.IOSer.io_Error));
  167.     CloseDevice(&SerMsg);
  168.     exit(0);
  169.    }
  170.  
  171. /* All set up, now execute the command that was given. */
  172.  
  173.   if (cflg) connect();                  /* CONNECT command */
  174.  
  175.   if (sflg)                             /* SEND command */ 
  176.    {
  177.     if (argc--) filnam = *argv++;       /* Get file to send */
  178.       else usage();
  179.     if (sendsw() == FALSE)              /* Send the file(s) */
  180.       printf("Send failed.\n");         /* Report failure */
  181.     else                                /*  or */
  182.       printf("OK\n");                   /* success */
  183.    }
  184.  
  185.   if (rflg)                             /* RECEIVE command */
  186.    {
  187.     if (recsw() == FALSE)               /* Receive the file */
  188.       printf("Receive failed.\n");      /* Report failure */
  189.     else                                /*  or */
  190.       printf("OK\n");                   /* success */
  191.    }
  192.   CloseDevice(&SerMsg);
  193.  }
  194.  
  195. usage()                                 /* Give message if user makes */
  196. {                                       /* a mistake in the command */
  197.   fprintf(stderr,
  198.      "Kermit -{{c|s|r}[d][i][b<baud>][e<esc char>]}[ <filename>[ <filename>[..]]]\n");
  199.   exit(0);
  200. }
  201.  
  202. /*
  203.  *      s e n d s w
  204.  *
  205.  *      Sendsw is the state table switcher for sending
  206.  *      files.  It loops until either it finishes, or
  207.  *      an error is encountered.  The routines called by
  208.  *      sendsw are responsible for changing the state.
  209.  *
  210.  */
  211.  
  212. sendsw()
  213. {
  214.  char sinit(),sfile(),seof(),sdata(),sbreak();
  215.  
  216.  state = 'S';                           /* Send initiate is the start state */
  217.  n = 0;                                 /* Initialize message number */
  218.  numtry = 0;                            /* Say no tries yet */
  219.  while(TRUE)                            /* Do this as long as necessary */
  220.   {
  221.    switch(state)
  222.     {
  223.      case 'D':  state = sdata();  break; /* Data-Send state */
  224.      case 'F':  state = sfile();  break; /* File-Send */
  225.      case 'Z':  state = seof();   break; /* End-of-File */
  226.      case 'S':  state = sinit();  break; /* Send-Init */
  227.      case 'B':  state = sbreak(); break; /* Break-Send */
  228.      case 'C':  return (TRUE);           /* Complete */
  229.      case 'A':  return (FALSE);          /* "Abort" */
  230.      default:   return (FALSE);          /* Unknown, fail */
  231.     }
  232.   }
  233. }
  234.  
  235.  
  236. /*
  237.  *      s i n i t
  238.  *
  239.  *      Send Initiate: Send my parameters, get other side's back.
  240.  */
  241.  
  242. char sinit()
  243. {
  244.   int num, len;                         /* Packet number, length */
  245.  
  246.   if (debug) fprintf(stderr,"sinit\n");
  247.   if (numtry++ > MAXTRY) return('A');   /* If too many tries, give up */
  248.   spar(packet);                         /* Fill up with init info */
  249.   if (debug) fprintf(stderr,"n = %d\n",n);
  250.  
  251.   spack('S',n,6,packet);                /* Send an S packet */
  252.   switch(rpack(&len,&num,recpkt))       /* What was the reply? */
  253.    {
  254.     case 'N':  return(state);           /* NAK */
  255.  
  256.     case 'Y':                           /* ACK */
  257.       if (n != num) return(state);      /* If wrong ACK, stay in S state */
  258.       rpar(recpkt);                     /* Get other side's init info */
  259.       if (eol == 0) eol = '\n';         /* Check and set defaults */
  260.       if (quote == 0) quote = '#';      /* Control-prefix quote */
  261.       numtry = 0;                       /* Reset try counter */
  262.       n = (n+1)%64;                     /* Bump packet count */
  263.       if (debug) fprintf(stderr,"Opening %s\n",filnam);
  264.       fd = open(filnam,0);              /* Open the file to be sent */
  265.       if (fd < 0) return('A');          /* if bad file descriptor, give up */
  266.       printf("Sending %s\n",filnam);
  267.       return('F');                      /* OK, switch state to F */
  268.  
  269.     case FALSE: return(state);          /* Receive failure, stay in S state */
  270.     default: return('A');               /* Anythig else, just "abort" */
  271.    }
  272.  }
  273.  
  274.  
  275. /*
  276.  *      s f i l e
  277.  *
  278.  *      Send File Header.
  279.  */
  280.  
  281. char sfile()
  282. {
  283.   int num, len;                         /* Packet number, length */
  284.  
  285.   if (debug) fprintf(stderr,"sfile\n");
  286.  
  287.   if (numtry++ > MAXTRY) return('A');   /* If too many tries, give up */
  288.   for (len=0; filnam[len] != '\0'; len++); /* Add up the length */
  289.  
  290.   spack('F',n,len,filnam);              /* Send an F packet */
  291.   switch(rpack(&len,&num,recpkt))       /* What was the reply? */
  292.    {                                    
  293.     case 'N':                           /* NAK, just stay in this state, */
  294.       if (n != (num=(--num<0)?63:num))  /*  unless NAK for next packet, */
  295.         return(state);                  /*  which is just like an ACK */
  296.                                         /*  for this packet, fall thru to... */
  297.     case 'Y':                           /* ACK */
  298.       if (n != num) return(state);      /* If wrong ACK, stay in F state */
  299.       numtry = 0;                       /* Reset try counter */
  300.       n = (n+1)%64;                     /* Bump packet count */
  301.       size = bufill(packet);            /* Get first data from file */
  302.       return('D');                      /* Switch state to D */
  303.  
  304.     case FALSE: return(state);          /* Receive failure, stay in F state */
  305.     default:    return('A');            /* Something esle, just "abort" */
  306.    }
  307. }
  308.  
  309.  
  310. /*
  311.  *      s d a t a
  312.  *
  313.  *      Send File Data
  314.  */
  315.  
  316. char sdata()
  317. {
  318.   int num, len;                         /* Packet number, length */
  319.  
  320.   if (numtry++ > MAXTRY) return('A');   /* If too many tries, give up */
  321.   spack('D',n,size,packet);             /* Send a D packet */
  322.  
  323.   switch(rpack(&len,&num,recpkt))       /* What was the reply? */
  324.    {                            
  325.     case 'N':                           /* NAK, just stay in this state, */
  326.       if (n != (num=(--num<0)?63:num))  /*  unless NAK for next packet, */
  327.         return(state);                  /*  which is just like an ACK */
  328.                                         /*  for this packet, fall thru to... */
  329.     case 'Y':                           /* ACK */
  330.       if (n != num) return(state);      /* If wrong ACK, fail */
  331.       numtry = 0;                       /* Reset try counter */
  332.       n = (n+1)%64;                     /* Bump packet count */
  333.       if ((size = bufill(packet)) == EOF) /* Get data from file */
  334.         return('Z');                    /* If EOF set state to that */
  335.       return('D');                      /* Got data, stay in state D */
  336.  
  337.     case FALSE: return(state);          /* Receive failure, stay in D */
  338.     default:    return('A');            /* Anything else, "abort" */
  339.    }
  340. }
  341.  
  342.  
  343. /*
  344.  *      s e o f
  345.  *
  346.  *      Send End-Of-File.
  347.  */
  348.  
  349. char seof()
  350. {
  351.   int num, len;                         /* Packet number, length */
  352.   if (debug) fprintf(stderr,"seof\n");
  353.   if (numtry++ > MAXTRY) return('A');   /* If too many tries, "abort" */
  354.   spack('Z',n,0,packet);                /* Send a 'Z' packet */
  355.   if (debug) fprintf(stderr,"seof1 ");
  356.   switch(rpack(&len,&num,recpkt))       /* What was the reply? */
  357.    {
  358.     case 'N':                           /* NAK, fail */
  359.       if (n != (num=(--num<0)?63:num))  /* ...unless for previous packet, */
  360.         return(state);                  /*  in which case, fall thru to ... */
  361.     case 'Y':                           /* ACK */
  362.       if (debug) fprintf(stderr,"seof2 ");
  363.       if (n != num) return(state);      /* If wrong ACK, hold out */
  364.       numtry = 0;                       /* Reset try counter */
  365.       n = (n+1)%64;                     /* and bump packet count */
  366.       if (debug) fprintf(stderr,"closing %s, ",filnam);
  367.       close(fd);                        /* Close the input file */
  368.       if (debug) fprintf(stderr,"ok, getting next file\n");
  369.  
  370.       if (gnxtfl() == FALSE)            /* No more files go? */
  371.         return('B');                    /* if not, break, EOT, all done */
  372.       if (debug) fprintf(stderr,"new file is %s\n",filnam);
  373.       fd = open(filnam,0);              /* Open next file to send */
  374.       if (fd<0) return ('B');           /* if bad file descriptor, give up*/
  375.                                         /* but close file just sent!! */
  376.       printf("Sending %s\n",filnam);
  377.       return('F');                      /* More files, switch state to F */
  378.  
  379.     case FALSE: return(state);          /* Receive failure, stay in state Z */
  380.     default:    return('A');            /* Something else, "abort" */
  381.    }
  382. }
  383.  
  384.  
  385. /*
  386.  *      s b r e a k
  387.  *
  388.  *      Send Break (EOT)
  389.  */
  390.  
  391. char sbreak()
  392. {
  393.   int num, len;                         /* Packet number, length */
  394.   if (debug) fprintf(stderr,"sbreak\n");
  395.   if (numtry++ > MAXTRY) return('A');   /* If too many tries "abort" */
  396.  
  397.   spack('B',n,0,packet);                /* Send a B packet */
  398.   switch (rpack(&len,&num,recpkt))      /* What was the reply? */
  399.    {
  400.     case 'N':                           /* NAK, fail */
  401.       if (n != (num=(--num<0)?63:num))  /* ...unless for previous packet, */
  402.         return(state);                  /*  in which case, fall thru to ... */
  403.  
  404.     case 'Y':                           /* ACK */
  405.       if (n != num) return(state);      /* If wrong ACK, fail */
  406.  
  407.       numtry = 0;                       /* Reset try counter */
  408.       n = (n+1)%64;                     /* and bump packet count */
  409.       return('C');                      /* switch state to Complete */
  410.  
  411.     case FALSE: return(state);          /* Receive failure, stay in state B */
  412.     default:    return ('A');           /* Other, "abort" */
  413.    }
  414. }
  415.  
  416.  
  417. /*
  418.  *      r e c s w
  419.  *
  420.  *      This is the state table switcher for receiving files.
  421.  */
  422.  
  423. recsw()
  424. {
  425.   char rinit(),rdata(),rfile();         /* Use these procedures */
  426.  
  427.   state = 'R';                          /* Receive is the start state */
  428.   n = 0;                                /* Initialize message number */
  429.   numtry = 0;                           /* Say no tries yet */
  430.  
  431.   while(TRUE) switch(state)             /* Do until done */
  432.    {
  433.     case 'D':   state = rdata(); break; /* Data receive state */
  434.     case 'F':   state = rfile(); break; /* File receive state */
  435.     case 'R':   state = rinit(); break; /* Send initiate state */
  436.     case 'C':   return(TRUE);           /* Complete state */
  437.     case 'A':   return(FALSE);          /* "Abort" state */
  438.     }
  439.   }
  440.     
  441. /*
  442.  *      r i n i t
  443.  *
  444.  *      Receive Initialization
  445.  */
  446.   
  447. char rinit()
  448. {
  449.   int len, num;                         /* Packet length, number */
  450.  
  451.   if (numtry++ > MAXTRY) return('A');   /* If too many tries, "abort" */
  452.   switch(rpack(&len,&num,packet))       /* Get a packet */
  453.   {
  454.    case 'S':                            /* Send-Init */
  455.      rpar(packet);                      /* Get the other side's init data */
  456.      spar(packet);                      /* Fill up packet with my init info */
  457.      spack('Y',n,6,packet);             /* ACK with my parameters */
  458.      oldtry = numtry;                   /* Save old try count */
  459.      numtry = 0;                        /* Start a new counter */
  460.      n = (n+1)%64;                      /* Bump packet number, mod 64 */
  461.      return('F');                       /* Enter File-Send state */
  462.  
  463.    case FALSE:  return (state);         /* Didn't get a packet, keep waiting */
  464.    default:     return('A');            /* Some other packet type, "abort" */
  465.   }
  466. }
  467.  
  468.  
  469. /*
  470.  *      r f i l e
  471.  *
  472.  *      Receive File Header
  473.  */
  474.  
  475. char rfile()
  476. {
  477.  int num, len;                          /* Packet number, length */
  478.  
  479.  if (numtry++ > MAXTRY) return('A');    /* "abort" if too many tries */
  480.  switch(rpack(&len,&num,packet))        /* Get a packet */
  481.   {
  482.    case 'S':                            /* Send-Init, maybe our ACK lost */
  483.      if (oldtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  484.      if (num == ((n==0)?63:n-1))        /* Previous packet, mod 64? */
  485.       {                                 /* Yes, ACK it again */
  486.        spar(packet);                    /* with our Send-Init parameters */
  487.        spack('Y',num,6,packet);         /*  ... */
  488.        numtry = 0;                      /* Reset try counter */
  489.        return(state);                   /* Stay in this state */
  490.       }
  491.      else return('A');                  /* Not previous packet, "abort" */
  492.  
  493.    case 'Z':                            /* End-Of-File */
  494.      if (oldtry++ > MAXTRY) return('A');
  495.      if (num == ((n==0)?63:n-1))        /* Previous packet, mod 64? */
  496.       {                                 /* Yes, ACK it again. */
  497.        spack('Y',num,0,0);
  498.        numtry = 0;
  499.        return(state);                   /* Stay in this state */
  500.       }
  501.      else return('A');                  /* Not previous packet, "abort" */
  502.  
  503.    case 'F':                            /* File Header, */
  504.      if (num != n) return('A');         /* which is what we really want */
  505.                                         /* The packet number must be right */
  506.      if (!getfil())                     /* Try to open a new file */
  507.       {
  508.        fprintf(stderr,"Could not create %s\n",filnam); /* Give up if can't */
  509.        return('A');
  510.       }
  511.      else                               /* OK, give message */
  512.        printf("Receiving %s\n",packet);
  513.      spack('Y',n,0,0);                  /* Acknowledge the file header */
  514.      oldtry = numtry;                   /* Reset try counters */
  515.      numtry = 0;                        /* ... */
  516.      n = (n+1)%64;                      /* Bump packet number, mod 64 */
  517.      return('D');                       /* Switch to Data state */
  518.  
  519.    case 'B':                            /* Break transmission (EOT) */
  520.      if (num != n) return ('A');        /* Need right packet number here */
  521.      spack('Y',n,0,0);                  /* Say OK */
  522.      return('C');                       /* Go to complete state */
  523.  
  524.    case FALSE: return(state);           /* Couldn't get packet, keep trying */
  525.    default:     return ('A');           /* Some other packet, "abort" */
  526.   }
  527. }
  528.  
  529.  
  530. /*
  531.  *      r d a t a
  532.  *
  533.  *      Receive Data
  534.  */
  535.  
  536. char rdata()
  537. {
  538.  int num, len;                          /* Packet number, length */
  539.  
  540.  if (numtry++ > MAXTRY) return('A');    /* "abort" if too many tries */
  541.  switch(rpack(&len,&num,packet))        /* Get packet */
  542.   {
  543.    case 'D':                            /* Got Data packet */
  544.      if (num != n)                      /* Right packet? */
  545.       {                                 /* No */
  546.        if (oldtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  547.        if (num == ((n==0)?63:n-1))      /* Else check packet number */
  548.         {                               /* Previous packet again? */
  549.          spack('Y',num,6,packet);       /* Yes, re-ACK it */
  550.          numtry = 0;                    /* Reset try counter */
  551.          return(state);                 /* Stay in D, don't write out data! */
  552.         }
  553.        else return('A');                /* sorry wrong number */
  554.       }
  555.                                         /* Got data with right packet number */
  556.      bufemp(packet,fd,len);             /* Write the data to the file */
  557.      spack('Y',n,0,0);                  /* Acknowledge the packet */
  558.      oldtry = numtry;                   /* Reset the try counters */
  559.      numtry = 0;                        /* ... */
  560.      n = (n+1)%64;                      /* Bump packet number, mod 64 */
  561.      return('D');                       /* Remain in data state */
  562.  
  563.    case 'F':                            /* Got a File Header */
  564.      if (oldtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  565.      if (num == ((n==0)?63:n-1))        /* Else check packet number */
  566.       {                                 /* It was the previous one */
  567.        spack('Y',num,0,0);              /* ACK it again */
  568.        numtry = 0;                      /* Reset try counter */
  569.        return(state);                   /* Stay in Data state */
  570.       }
  571.      else return('A');                  /* Not previous packet, "abort" */
  572.  
  573.    case 'Z':                            /* End-Of-File */
  574.      if (num != n) return('A');         /* Must have right packet number */
  575.      spack('Y',n,0,0);                  /* OK, ACK it. */
  576.      close(fd);                         /* Close the file */
  577.      n = (n+1)%64;                      /* Bump packet number */
  578.      return('F');                       /* Go back to Receive File state */
  579.  
  580.    case FALSE:  return(state);          /* No packet came, keep waiting */
  581.    default:     return('A');            /* Some other packet, "abort" */
  582.   }
  583. }
  584.  
  585. /*
  586.  *      c o n n e c t
  587.  *
  588.  *      Establish a virtual terminal connection with the remote host.
  589.  *
  590.  */
  591.  
  592. connect()
  593. {
  594. }
  595.  
  596. /*
  597.  *      KERMIT utilities.
  598.  */
  599.  
  600. /* tochar converts a control character to a printable one by adding a space */
  601.  
  602. char tochar(ch)
  603. char ch;
  604. {
  605.   return((char)(ch + ' '));     /* make sure not a control char */
  606. }
  607.  
  608.  
  609. /* unchar undoes tochar */
  610.  
  611. char unchar(ch)
  612. char ch;
  613. {
  614.   return((char)(ch - ' '));     /* restore char */
  615. }
  616.  
  617.  
  618. /*
  619.  * ctl turns a control character into a printable character by toggling the
  620.  * control bit (ie. ^A becomes A and A becomes ^A).
  621.  */
  622.  
  623. char ctl(ch)
  624. char ch;
  625. {
  626.  return((char)(ch ^ 64));       /* toggle the control bit */
  627. }
  628.  
  629.  
  630. /*
  631.  *      s p a c k
  632.  *
  633.  *      Send a Packet
  634.  */
  635.  
  636. spack(type,num,len,data)
  637. char type, *data;
  638. int num, len;
  639. {
  640.   int i;                                /* Character loop counter */
  641.   char chksum, buffer[100];             /* Checksum, packet buffer */
  642.   register char *bufp;                  /* Buffer pointer */
  643.   
  644.   bufp = buffer;                        /* Set up buffer pointer */
  645.   for (i=1; i<=pad; i++)
  646.     WriteSer(&padchar,1);               /* Issue any padding */
  647.  
  648.   *bufp++ = SOH;                        /* Packet marker, ASCII 1 (SOH) */
  649.   chksum = tochar(len+3);               /* Initialize the checksum */
  650.   *bufp++ = tochar(len+3);              /* Send the character count */
  651.   chksum = chksum + tochar(num);        /* Init checksum */
  652.   *bufp++ = tochar(num);                /* Packet number */
  653.   chksum = chksum + type;               /* Accumulate checksum */
  654.   *bufp++ = type;                       /* Packet type */
  655.  
  656.   for (i=0; i<len; i++)                 /* Loop for all data characters */
  657.    {
  658.     *bufp++ = data[i];                  /* Get a character */
  659.     chksum = chksum+data[i];            /* Accumulate checksum */
  660.    }
  661.   chksum = (chksum + (chksum & 192) / 64) & 63; /* Compute final checksum */
  662.   *bufp++ = tochar(chksum);             /* Put it in the packet */
  663.   *bufp = eol;                          /* Extra-packet line terminator */
  664.  
  665.   WriteSer(buffer,bufp-buffer+1);       /* Send the packet */
  666.  
  667.   if (debug) putc('.',stderr);
  668. }
  669.  
  670. /*
  671.  *  r p a c k
  672.  *
  673.  *  Read a Packet
  674.  *
  675.  */
  676.  
  677. rpack(len,num,data)
  678. int *len, *num;                         /* Packet length, number */
  679. char *data;                             /* Packet data */
  680. {
  681.  int i, done;                           /* Data character number, loop exit */
  682.  char chksum, t, type;                  /* Checksum, current char, pkt type */
  683.  
  684.  t = '\0';
  685.  
  686.  while (t != SOH)                       /* Wait for packet header */
  687.   {
  688.  
  689.    ReadSer(&t,1);
  690.  
  691.    if (!image) t &= 0177;               /* Handle parity */
  692.   }
  693.  
  694.  done = FALSE;                          /* Got SOH, init loop */
  695.  while (!done)                          /* Loop to get a packet */
  696.   {
  697.  
  698.    ReadSer(&t,1);                       /* Get character */
  699.  
  700.    if (!image) t &= 0177;               /* Handle parity */
  701.    if (t == SOH) continue;              /* Resynchronize if SOH */
  702.  
  703.    chksum = t;                          /* Start the checksum */
  704.    *len = unchar(t)-3;                  /* Character count */
  705.  
  706.    ReadSer(&t,1);                       /* Get character */
  707.  
  708.    if (!image) t &= 0177;               /* Handle parity */
  709.    if (t == SOH) continue;              /* Resynchronize if SOH */
  710.    chksum = chksum + t;                 /* Accumulate checksum */
  711.    *num = unchar(t);                    /* Packet number */
  712.  
  713.    ReadSer(&t,1);                       /* Get character */
  714.  
  715.    if (!image) t &= 0177;               /* Handle parity */
  716.    if (t == SOH) continue;              /* Resynchronize if SOH */
  717.    chksum = chksum + t;                 /* Accumulate checksum */
  718.    type = t;                            /* Packet type */
  719.  
  720.    for (i=0; i<*len; i++)               /* The data itself, if any */
  721.     {                                   /* Loop for character count */
  722.  
  723.      ReadSer(&t,1);                     /* Get character */
  724.  
  725.      if (!image) t &= 0177;             /* Handle parity */
  726.      if (t == SOH) continue;            /* Resynch if SOH */
  727.      chksum = chksum + t;               /* Accumulate checksum */
  728.      data[i] = t;                       /* Put it in the data buffer */
  729.     }
  730.    data[*len] = 0;                      /* Mark the end of the data */
  731.  
  732.    ReadSer(&t,1);                       /* Get last character (checksum) */
  733.  
  734.    if (!image) t &= 0177;               /* Handle parity */
  735.    if (t == SOH) continue;              /* Resynchronize if SOH */
  736.    done = TRUE;                         /* Got checksum, done */
  737.   }
  738.  
  739.  chksum = (chksum + (chksum & 192) / 64) & 63; /* Fold bits 7,8 into chksum */
  740.  if (chksum != unchar(t)) return(FALSE); /* Check the checksum, fail if bad */
  741.  
  742.  return((int)(type));                   /* All OK, return packet type */
  743. }
  744.  
  745.  
  746.  
  747. /*
  748.  *      b u f i l l
  749.  *
  750.  *      Get a bufferful of data from the file that's being sent.
  751.  *      Only control-quoting is done; 8-bit & repeat count prefixes are
  752.  *      not handled.
  753.  */
  754.  
  755. bufill(buffer)
  756. char buffer[];                          /* Buffer */
  757.  {
  758.   int i;                                /* Loop index */
  759.   char t,t7;
  760.   i = 0;                                /* Init data buffer pointer */
  761.   while(read(fd,&t,1) > 0)              /* Get the next character */
  762.    {
  763.     if (image)                          /* In 8-bit mode? */
  764.      {
  765.       t7 = t & 0177;                    /* Yes, look at low-order 7 bits */
  766.       if (t7 < SP || t7==DEL || t7==quote) /* Control character? */
  767.        {                                /*    Yes, */
  768.         buffer[i++] = quote;            /*    quote this character */
  769.         if (t7 != quote) t = ctl(t);    /* and uncontrollify */
  770.        }
  771.      }
  772.     else                                /* Else, ASCII text mode */
  773.      {
  774.       t &= 0177;                        /* Strip off the parity bit */
  775.       if (t < SP || t == DEL || t == quote) /* Control character? */
  776.        {                                /* Yes */
  777.         if (t=='\n')                    /* If newline, squeeze CR in first */
  778.          {
  779.           buffer[i++] = quote;
  780.           buffer[i++] = ctl('\r');
  781.          }
  782.         buffer[i++] = quote;            /* Insert quote */
  783.         if (t != quote) t=ctl(t);       /* Uncontrollified the character */
  784.        }
  785.      }
  786.     buffer[i++] = t;                    /* Deposit the character itself */
  787.     if (i >= spsiz-8) return(i);        /* Check length */
  788.    }
  789.   if (i==0) return(EOF);                /* Wind up here only on EOF */
  790.   return(i);                            /* Handle partial buffer */
  791. }
  792.  
  793. /*
  794.  *      b u f e m p
  795.  *
  796.  *      Get data from an incoming packet into a file.
  797.  */
  798.  
  799. bufemp(buffer,fd,len)
  800. char buffer[];                          /* Buffer */
  801. int fd, len;                            /* File pointer, length */
  802.  {
  803.   int i;                                /* Counter */
  804.   char t;                               /* Character holder */
  805.  
  806.   for (i=0; i<len; i++)                 /* Loop thru the data field */
  807.    {
  808.     t = buffer[i];                      /* Get character */
  809.     if (t == MYQUOTE)                   /* Control quote? */
  810.      {                                  /* Yes */
  811.       t = buffer[++i];                  /* Get the quoted character */
  812.       if ((t & 0177) != MYQUOTE)        /* Low order bits match quote char? */
  813.         t = ctl(t);                     /* No, uncontrollify it */
  814.      }
  815.     if (image || (t != CR))             /* Don't pass CR in text mode */
  816.       write(fd,&t,1);                   /* Put the char in the file */
  817.    }
  818.  }
  819.  
  820.  
  821. /*
  822.  *      g e t f i l
  823.  *
  824.  *      Open a new file
  825.  */
  826.  
  827. getfil()
  828. {
  829.   if (gnxtfl() == FALSE) filnam = packet;
  830.   fd = creat(filnam,0644);
  831.   return (fd > 0);                      /* Return false if file won't open */
  832. }
  833.  
  834. /*
  835.  *      g n x t f l
  836.  *
  837.  *      Get next file in a file group
  838.  */
  839.  
  840. gnxtfl()
  841. {
  842.   if (debug) fprintf(stderr, "gnxtfl\n");
  843.   if (argc--) filnam = *argv++;
  844.     else return FALSE;                  /* If no more, fail */
  845.   return TRUE;                          /* else succeed */
  846. }
  847.  
  848. /*
  849.  *      s p a r
  850.  *
  851.  *      Fill the data array with my send-init parameters
  852.  *
  853.  */
  854.  
  855. spar(data)
  856. char data[];
  857. {
  858.   data[0] = tochar(MAXPACK);            /* Biggest packet I can receive */
  859.   data[1] = tochar(MYTIME);             /* When I want to be timed out */
  860.   data[2] = tochar(MYPAD);              /* How much padding I need */
  861.   data[3] = ctl(MYPCHAR);               /* Padding character I want */
  862.   data[4] = tochar(MYEOL);              /* End-Of-Line character I want */
  863.   data[5] = MYQUOTE;                    /* Control-Quote character I send */
  864. }
  865.  
  866.  
  867. /*      r p a r
  868.  *
  869.  *      Get the other host's send-init parameters
  870.  *
  871.  */
  872.  
  873. rpar(data)
  874. char data[];
  875. {
  876.   spsiz = unchar(data[0]);              /* Maximum send packet size */
  877.   timint = unchar(data[1]);             /* When I should time out */
  878.   pad = unchar(data[2]);                /* Number of pads to send */
  879.   padchar = ctl(data[3]);               /* Padding character to send */
  880.   eol = unchar(data[4]);                /* EOL character I must send */
  881.   quote = data[5];                      /* Incoming data quote character */
  882. }
  883.  
  884.  
  885. /*      R e a d S e r
  886.  *
  887.  *      Read characters from the serial.device
  888.  *
  889.  */
  890.  
  891. ReadSer(data,length)
  892. char *data;
  893. int length;
  894. {
  895.   SerMsg.IOSer.io_Command = CMD_READ;
  896.   SerMsg.IOSer.io_Flags = NULL;
  897.   SerMsg.IOSer.io_Length = length;
  898.   SerMsg.IOSer.io_Data = (APTR)(data);
  899.  
  900.   SendIO(&SerMsg);
  901.   WaitIO(&SerMsg);
  902.  
  903.   if(SerMsg.IOSer.io_Error != 0)
  904.   {
  905.     printf("\nserial.device read error = %u:\n\n"
  906.            ,(unsigned)(SerMsg.IOSer.io_Error));
  907.     CloseDevice(&SerMsg);
  908.     exit(0);
  909.   }
  910. }
  911.  
  912. /*      W r i t e S e r
  913.  *
  914.  *      Write characters to the serial.device
  915.  *
  916.  */
  917.  
  918. WriteSer(data,length)
  919. char *data;
  920. int length;
  921. {
  922.   SerMsg.IOSer.io_Command = CMD_WRITE;
  923.   SerMsg.IOSer.io_Flags = NULL;
  924.   SerMsg.IOSer.io_Length = length;
  925.   SerMsg.IOSer.io_Data = (APTR)(data);
  926.  
  927.   SendIO(&SerMsg);
  928.   WaitIO(&SerMsg);
  929.  
  930.   if(SerMsg.IOSer.io_Error != 0)
  931.   {
  932.     printf("\nserial.device write error = %u:\n\n"
  933.            ,(unsigned)(SerMsg.IOSer.io_Error));
  934.     CloseDevice(&SerMsg);
  935.     exit(0);
  936.   }
  937. }
  938.